import { IMode } from "./IMode";
import { Point } from "pixi.js";
import { Transform as TransformBar } from "../../views/OperatorBar/Transform";
import { ArmatureController } from "../ArmatureController";
import { emitter } from "../../../eventEmitter";
import { ItransformableItem } from "../ITransformableItem";

//export type CursorState = "selectedEmpty" | "inSelected" | "inUnSelected" | "inSpace";
//export type ActionType = "move" | "rotate" | "scale";
type CursorState = {
    state: "selectedEmpty" | "inSelected" | "inUnSelected" | "inSpace" | "inMoveX" | "inMoveY" | "inScale";
    target: ItransformableItem | null;
};

export class TransformController implements IMode {
    private _ctrl: ArmatureController;
    private _preDragMovePoint = new Point();
    private _curDragMovePoint = new Point();
    public operateBar: TransformBar;
    private _cursorState: CursorState = { state: "selectedEmpty", target: null };

    constructor(ctrl: ArmatureController) {
        this._ctrl = ctrl;
        this.operateBar = new TransformBar();
        this._ctrl.view.addChild(this.operateBar);
        this.operateBar.visible = false;
    }

    private _moveBoneItem(bone: ItransformableItem, pre: Point, cur: Point, onlyX = false, onlyY = false): void {
        // pre = this._ctrl.view.toWorld(pre);
        // cur = this._ctrl.view.toWorld(cur);

        if (onlyX) {
            cur.y = pre.y;
        }

        if (onlyY) {
            cur.x = pre.x;
        }

        let parent = bone.parent;
        if (parent) {
            pre = parent.view.toLocal(pre);
            cur = parent.view.toLocal(cur);
        } else {
            pre = this._ctrl.view.toWorld(pre);
            cur = this._ctrl.view.toWorld(cur);
        }

        let offsetX = cur.x - pre.x;
        let offsetY = cur.y - pre.y;

        bone.transform.x += offsetX;
        bone.transform.y += offsetY;
        bone.updateMatrixByLocalTransform();
        bone.updateSubItems();
    }

    private _moveAction(onlyX = false, onlyY = false): void {
        let armatureCtrl = this._ctrl;
        let items = armatureCtrl.selectedItemManager.getMinItems();
        if (items) {
            for (const item of items) {
                this._moveBoneItem(item, this._preDragMovePoint, this._curDragMovePoint, onlyX, onlyY);
            }
        }
        this._preDragMovePoint.copyFrom(this._curDragMovePoint);
        this.updateOperateBar(true);
    }

    /*
    private _moveActionBak(onlyX = false, onlyY = false): void {
        let armatureCtrl = this._ctrl;
        let offsetX = this._curDragMovePoint.x - this._preDragMovePoint.x;
        let offsetY = this._curDragMovePoint.y - this._preDragMovePoint.y;
        if (onlyX) {
            offsetY = 0;
        }

        if (onlyY) {
            offsetX = 0;
        }

        this._preDragMovePoint.copyFrom(this._curDragMovePoint);

        //只操作最高节点
        let bones = armatureCtrl.getMinBones();
        if (bones) {
            for (const bone of bones) {
                bone.view.position.x += offsetX;
                bone.view.position.y += offsetY;
                bone.updateLocalMatrix();
                bone.updateSubItems();
            }
        }
        this.updateOperateBar(true);
    }

    private _rotateActionBak(): void {
        let armatureCtrl = this._ctrl;

        //只操作最高节点
        let bones = armatureCtrl.getMinBones();
        if (bones) {
            for (const bone of bones) {
                bone.view.rotateBetweenPoint(this._preDragMovePoint, this._curDragMovePoint);
                bone.updateLocalMatrix();
                bone.updateSubItems();
            }
        }
        this._preDragMovePoint.copyFrom(this._curDragMovePoint);
        this.updateOperateBar(true);
    }
    */

    private _rotateItem(bone: ItransformableItem, pre: Point, cur: Point) {
        pre = this._ctrl.view.toWorld(pre);
        cur = this._ctrl.view.toWorld(cur);
        let parent = bone.parent;
        let position = bone.view.position;
        if (parent) {
            pre = parent.view.toLocal(pre);
            cur = parent.view.toLocal(cur);
            position = parent.view.toLocal(position);
        }

        let rotationTo = Math.atan2((cur.y - position.y), (cur.x - position.x));
        let rotationFrom = Math.atan2((pre.y - position.y), (pre.x - position.x));
        let rotation = rotationTo - rotationFrom;
        bone.transform.rotation += rotation;
        bone.updateMatrixByLocalTransform();
        bone.updateSubItems();
    }

    private _rotateAction(): void {
        let armatureCtrl = this._ctrl;

        //只操作最高节点
        let items = armatureCtrl.selectedItemManager.getMinItems();
        if (items) {
            for (const item of items) {
                this._rotateItem(item, this._preDragMovePoint, this._curDragMovePoint);
            }
        }
        this._preDragMovePoint.copyFrom(this._curDragMovePoint);
        this.updateOperateBar(true);
    }

    private _scaleAction(): void {
        // let armatureCtrl = this._ctrl;
        // let dist = Math.sqrt(Math.pow((this._curDragMovePoint.x - this._preDragMovePoint.x), 2) + Math.pow((this._curDragMovePoint.y - this._preDragMovePoint.y), 2));

        // let rotate = Math.atan2((this._curDragMovePoint.y - this._preDragMovePoint.y), (this._curDragMovePoint.x - this._preDragMovePoint.x));
        // rotate = rotate + 135 * Math.PI / 180;
        // let diff = dist * Math.cos(rotate);
        // let scale = diff / 40;

        // let bones = armatureCtrl.getMinBones();
        // if (bones) {
        //     for (const bone of bones) {
        //         bone.view.scale.x += scale;
        //         bone.view.scale.y += scale;
        //         console.log("bone scale", bone.view.scale.x, bone.view.scale.y);
        //         if (bone.)

        //             bone.updateLocalMatrix();
        //         bone.updateSubItems();
        //     }
        // }
        // this._preDragMovePoint.copyFrom(this._curDragMovePoint);
        // this.updateOperateBar(true);
    }

    public onDragMove(event: any): void {
        this._curDragMovePoint.set(event.global.x, event.global.y);
        switch (this._cursorState.state) {
            case "inSelected":
                this._moveAction();
                break;

            case "inSpace":
                this._rotateAction();
                break;

            case "inMoveX":
                this._moveAction(true, false);
                break;

            case "inMoveY":
                this._moveAction(false, true);
                break;
            case "inScale":
                this._scaleAction();
                break;

            default:
                break;
        }
    }

    public onDragMoveEnd(event: any): void {
    }

    private _clickHandler() {
        let armatureCtrl = this._ctrl;

        switch (this._cursorState.state) {
            case "inUnSelected":
                if (this._cursorState.target) {
                    armatureCtrl.selectedItemManager.clearSelectedItems();
                    armatureCtrl.selectedItemManager.addSelectItem(this._cursorState.target);
                }

                break;

            default:
                break;
        }
    }

    public onDragStart(event: any): void {
        let point = new Point(event.global.x, event.global.y);
        this.updateCursorState(point);

        // if (this._ctrl.view.monster.containsPoint(point)) {
        //     console.log("monstert click");
        //     let armatureCtrl = this._ctrl;
        //     armatureCtrl.skinController.createDisplay(monster, null, armatureCtrl.boneControllers[0]);
        //     rootStore.propertyStore.setBoneData("vvvvvv");
        //     return;
        // }


        //let armatureCtrl = this._ctrl;
        this._preDragMovePoint.set(event.global.x, event.global.y);
        this._clickHandler();
        this.updateCursorState(point);

        this.updateOperateBar(true);
    }

    private _hoverHandler() {
        let armatureCtrl = this._ctrl;
        let item = this._cursorState.target;
        if (item) {
            if (armatureCtrl.hoverItem == null || armatureCtrl.hoverItem !== item) {
                item.hoverEnter();
                if (armatureCtrl.hoverItem) {
                    armatureCtrl.hoverItem.hoverLeave();
                }
                armatureCtrl.hoverItem = item;
            }
        } else {
            if (armatureCtrl.hoverItem) {
                armatureCtrl.hoverItem.hoverLeave();
                armatureCtrl.hoverItem = null;
            }
        }
    }

    public onHover(event: any): void {
        let point = new Point(event.global.x, event.global.y);
        this.updateCursorState(point);
        this._hoverHandler();
    }

    public updateOperateBar(visible: boolean): void {
        let armatureCtrl = this._ctrl;

        if (visible) {
            let operateItem = armatureCtrl.selectedItemManager.getOperateItem();
            console.log("operate bar", operateItem);
            if (operateItem) {
                this.operateBar.visible = true;
                this.operateBar.position.set(operateItem.view.position.x, operateItem.view.position.y);
                this.operateBar.target = operateItem;
                console.log("operateBar", this.operateBar);
            }
        } else {
            this.operateBar.target = null;
            this.operateBar.visible = false;
        }
    }

    public onEnter(): void {
        emitter.emit("changeCursor", "transform");
        this._cursorState.state = "selectedEmpty";
        this._cursorState.target = null;
        this.updateOperateBar(true);
    }

    public onLeave(): void {
        this.updateOperateBar(false);
    }

    public getCursorState(position: Point): CursorState {
        const armatureCtrl = this._ctrl;
        let ret: CursorState = {
            state: "selectedEmpty",
            target: null,
        };

        if (armatureCtrl.selectedItemManager.selectedItemsSet.size > 0) {
            if (this.operateBar.containsPoint(position)) {
                ret.state = "inMoveX";
                ret.target = this.operateBar.target;
                return ret;

            } else if (this.operateBar.arrowDown.containsPoint(position)) {
                ret.state = "inMoveY";
                ret.target = this.operateBar.target;
                return ret;
            }
        }

        for (const bone of armatureCtrl.boneControllers) {
            if (bone.isContainPoint(position)) {
                if (armatureCtrl.selectedItemManager.selectedItemsSet.has(bone)) {
                    ret.state = "inSelected";
                    ret.target = bone;
                    return ret;
                } else {
                    ret.state = "inUnSelected";
                    ret.target = bone;
                    return ret;
                }
            }
        }

        let displayList = armatureCtrl.getCurDisplayList();
        if (displayList) {
            for (const display of displayList) {
                if (display.isContainPoint(position)) {
                    if (armatureCtrl.selectedItemManager.selectedItemsSet.has(display)) {
                        ret.state = "inSelected";
                        ret.target = display;
                        return ret;
                    } else {
                        ret.state = "inUnSelected";
                        ret.target = display;
                        return ret;
                    }
                }
            }
        }

        if (armatureCtrl.selectedItemManager.selectedItemsSet.size > 0) {
            console.log("inSpace ret");
            ret.state = "inSpace";
        }
        return ret;
    }

    public updateCursorStyle() {
        switch (this._cursorState.state) {
            case "inSelected":
                console.log("change cursor2 move");
                emitter.emit("changeCursor", "move");
                break;
            case "inUnSelected":
                console.log("change cursor2 transform1");
                emitter.emit("changeCursor", "transform");
                break;
            case "inSpace":
                console.log("change cursor2 rotate");
                emitter.emit("changeCursor", "rotate");
                break;
            case "selectedEmpty":
                console.log("change cursor2 transform2");
                emitter.emit("changeCursor", "transform");
                break;
            case "inScale":
                console.log("change cursor2 scale2");
                emitter.emit("changeCursor", "scale");
                break;
            case "inMoveX":
                emitter.emit("changeCursor", "move");
                break;
            case "inMoveY":
                emitter.emit("changeCursor", "move");
                break;
            default:
                break;
        }
    }

    /*
    switch mode
    hover
    */
    public updateCursorState(position: Point): void {
        const cursorState = this.getCursorState(position);
        if (this._cursorState.state !== cursorState.state || this._cursorState.target !== cursorState.target) {
            this._cursorState.state = cursorState.state;
            this._cursorState.target = cursorState.target;

            this.updateCursorStyle();
        }
    }
}